package cn.smile.business.notebook.impl;

import cn.hutool.core.thread.ThreadUtil;
import cn.smile.bean.dto.core.FileViewDTO;
import cn.smile.bean.dto.notebook.NotebookDTO;
import cn.smile.bean.dto.core.DicInfoDTO;
import cn.smile.bean.dto.core.SysUserDTO;
import cn.smile.bean.dto.wechat.WechatDevelopConfigDTO;
import cn.smile.bean.entity.notebook.Notebook;
import cn.smile.bean.form.core.user.QueryUserForm;
import cn.smile.bean.form.notebook.AddNotebookForm;
import cn.smile.bean.form.notebook.QueryNotebookForm;
import cn.smile.bean.form.notebook.UpdateNotebookForm;
import cn.smile.bean.form.wechat.api.ArticleDraftForm;
import cn.smile.business.core.IDicInfoService;
import cn.smile.business.core.ISysUserService;
import cn.smile.business.notebook.INotebookImageService;
import cn.smile.business.notebook.INotebookService;
import cn.smile.business.notebook.INotebookShareService;
import cn.smile.business.wechat.IWeChatApiService;
import cn.smile.business.wechat.IWeChatDevConService;
import cn.smile.commons.constant.NumberConstant;
import cn.smile.commons.domain.BaseServiceImpl;
import cn.smile.commons.enums.core.DicParentEnum;
import cn.smile.commons.enums.wechat.WeChatPublishStatusEnum;
import cn.smile.commons.exceptions.BusinessException;
import cn.smile.commons.response.MyResponseCode;
import cn.smile.repository.notebook.NotebookMapper;
import cn.smile.utils.BeanCopy;
import cn.smile.utils.FileUtil;
import cn.smile.utils.ThreadPoolUtil;
import cn.smile.utils.UserUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;

@Slf4j
@Service
public class NotebookServiceImpl extends BaseServiceImpl<NotebookMapper, Notebook> implements INotebookService {
    @Resource
    private INotebookShareService shareService;
    @Resource
    private INotebookImageService imageService;
    @Resource
    private IDicInfoService dicService;
    @Resource
    private ISysUserService userService;
    @Resource
    private IWeChatDevConService configService;
    @Resource
    private IWeChatApiService apiService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addNotebook(AddNotebookForm form) {
        log.info("[NotebookServiceImpl].[addNotebook] ------> 新增日记记录 Start");
        if (ObjectUtils.isEmpty(form.getRecordDate())) {
            //无记录时间, 默认今天
            form.setRecordDate(new Date());
        }
        this.checkParams(form);
        Notebook entity = BeanCopy.copyBean(form, Notebook.class);
        entity.setUserId(UserUtil.getUserInfo().getId());
        entity.setPublishStatus(WeChatPublishStatusEnum.UNPUBLISH.getSn());
        boolean flag = super.create(entity);
        if (flag) {
            //保存图片及共享关系
            this.saveOther(form, entity.getId());
            String notebookId = entity.getId();
            ThreadPoolUtil.newTask(() -> publishToWeChat(notebookId));
        }
        log.info("[NotebookServiceImpl].[addNotebook] ------> 新增日记记录 End, flag = {}", flag);
        return flag;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateNotebook(UpdateNotebookForm form) {
        log.info("[NotebookServiceImpl].[updateNotebook] ------> 更新日记记录 Start");
        super.get(form.getId());
        Notebook entity = BeanCopy.copyBean(form, Notebook.class);
        entity.setUserId(UserUtil.getUserInfo().getId());
        boolean flag = super.update(entity);
        if (flag) {
            //保存图片及共享关系
            this.saveOther(form, entity.getId());
        }
        log.info("[NotebookServiceImpl].[updateNotebook] ------> 更新日记记录 End, flag = {}", flag);
        return flag;
    }

    @Override
    public IPage<NotebookDTO> getPage(QueryNotebookForm form) {
        log.info("[NotebookServiceImpl].[getPage] ------> 分页查询日记 Start, form = {}", form);
        Page<Notebook> basePage = baseMapper.selectPage(form.queryPage(), this.getQueryParams(form));
        IPage<NotebookDTO> dataPage = BeanCopy.copyPage(basePage, NotebookDTO.class);
        this.setDetail(dataPage.getRecords());
        log.info("[NotebookServiceImpl].[getPage] ------> 分页查询日记 End");
        return dataPage;
    }

    @Override
    public List<NotebookDTO> getList(QueryNotebookForm form) {
        log.info("[NotebookServiceImpl].[getList] ------> 列表查询日记 Start, form = {}", form);
        List<Notebook> baseList = baseMapper.selectList(this.getQueryParams(form));
        List<NotebookDTO> dataList = BeanCopy.copyList(baseList, NotebookDTO.class);
        this.setDetail(dataList);
        log.info("[NotebookServiceImpl].[getList] ------> 列表查询日记 End");
        return dataList;
    }

    @Override
    public NotebookDTO getEntityById(String id) {
        log.info("[NotebookServiceImpl].[getEntityById] ------> 根据日记ID查询日记详情 Start, id = {}", id);
        Notebook base = super.get(id);
        NotebookDTO entity = BeanCopy.copyBean(base, NotebookDTO.class);
        this.setDetail(Lists.newArrayList(entity));
        log.info("[NotebookServiceImpl].[getEntityById] ------> 根据日记ID查询日记详情 End");
        return entity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delEntity(String id) {
        log.info("[NotebookServiceImpl].[delEntity] ------> 根据日记ID删除日记 Start, id = {}", id);
        boolean flag = super.delById(id);
        if (flag) {
            //删除共享和图片附件
            this.saveOther(new AddNotebookForm(), id);
        }
        log.info("[NotebookServiceImpl].[delEntity] ------> 根据日记ID删除日记 End, flag = {}", flag);
        return flag;
    }

    @Override
    public Integer countRecordDay(String userId) {
        log.info("[NotebookServiceImpl].[countRecordDay] ------> 统计指定用户记录天数 Start, userId = {}", userId);
        Integer recordDay = baseMapper.countRecordDay(userId);
        log.info("[NotebookServiceImpl].[countRecordDay] ------> 统计指定用户记录天数 End, userId = {}, recordDay = {}", userId, recordDay);
        return recordDay;
    }

    @Override
    public Integer countNotebookNum(String userId) {
        log.info("[NotebookServiceImpl].[countNotebookNum] ------> 统计指定用户日记数量 Start, userId = {}", userId);
        Long notebookNum = baseMapper.selectCount(new QueryWrapper<Notebook>().lambda().eq(Notebook::getDeleted, Boolean.FALSE).eq(Notebook::getUserId, userId));
        log.info("[NotebookServiceImpl].[countNotebookNum] ------> 统计指定用户日记数量 End, userId = {}, notebookNum = {}", userId, notebookNum);
        return Integer.parseInt(notebookNum.toString());
    }

    @Override
    public Integer shareNumToUser(String userId) {
        log.info("[NotebookServiceImpl].[shareNumToUser] ------> 统计分享给指定用户的日记数量 Start, userId = {}", userId);
        List<String> ids = shareService.getShareByUserId(userId);
        Integer shareNum = ids.size();
        log.info("[NotebookServiceImpl].[shareNumToUser] ------> 统计分享给指定用户的日记数量 End, userId = {}, shareNum = {}", userId, shareNum);
        return shareNum;
    }

    /**
     * 写入详细信息
     *
     * @param dataList 数据集合
     */
    private void setDetail(List<NotebookDTO> dataList) {
        if (!ObjectUtils.isEmpty(dataList)) {

            List<String> ids = Lists.newArrayList();
            Set<String> userIds = Sets.newHashSet();
            dataList.forEach(entity -> {
                ids.add(entity.getId());
                userIds.add(entity.getUserId());
            });
            QueryUserForm form = new QueryUserForm();
            form.setIds(CollectionUtils.isEmpty(userIds) ? Lists.newArrayList(UUID.randomUUID().toString()) : Lists.newArrayList(userIds));
            Map<String, SysUserDTO> userMap = userService.queryUserMap(form);
            Map<String, List<SysUserDTO>> shareMap = shareService.getShareMap(ids);
            Map<String, List<String>> imageMap = imageService.getImageMap(ids);
            for (NotebookDTO entity : dataList) {
                if (userMap.containsKey(entity.getUserId())) {
                    SysUserDTO user = userMap.get(entity.getUserId());
                    entity.setUserAvatar(user.getAvatar());
                    entity.setUserNickName(user.getNickName());
                }
                if (!ObjectUtils.isEmpty(entity.getPublishStatus())) {
                    entity.setPublishStatusName(WeChatPublishStatusEnum.get(entity.getPublishStatus()).getMsg());
                }
                //写入字典
                if (!ObjectUtils.isEmpty(entity.getRecordTypeDic())) {
                    Map<Integer, DicInfoDTO> dicMap = dicService.getDicMap(DicParentEnum.NOTEBOOK_TYPE.getId(), entity.getUserId());
                    entity.setRecordTypeDicValue(Lists.newArrayList(String.valueOf(entity.getRecordTypeDic())));
                    if (dicMap.containsKey(entity.getRecordTypeDic())) {
                        entity.setRecordTypeDicName(dicMap.get(entity.getRecordTypeDic()).getDicName());
                    }
                }
                if (imageMap.containsKey(entity.getId())) {
                    entity.setImagesFiles(imageMap.get(entity.getId()));
                    List<FileViewDTO> imageDetailFiles = Lists.newArrayList();
                    for (String imageUrl : entity.getImagesFiles()) {
                        FileViewDTO dto = new FileViewDTO();
                        dto.setUrl(imageUrl);
                        dto.setName(FileUtil.urlToFileName(imageUrl));
                        imageDetailFiles.add(dto);
                    }
                    entity.setImageDetailFiles(imageDetailFiles);
                }
                if (shareMap.containsKey(entity.getId())) {
                    List<SysUserDTO> shareList = shareMap.get(entity.getId());
                    List<String> shareUserIds = Lists.newArrayList();
                    if (!CollectionUtils.isEmpty(shareList)) {
                        StringBuilder names = new StringBuilder();
                        int index = NumberConstant.ZERO;
                        for (SysUserDTO share : shareList) {
                            shareUserIds.add(share.getId());
                            names.append(share.getNickName());
                            index++;
                            if (index != shareList.size()) {
                                names.append(",");
                            }
                        }
                        entity.setShareNames(names.toString());
                    }
                    entity.setShareIdList(shareUserIds);
                }
            }
        }
    }

    /**
     * 组装数据库查询参数
     *
     * @param form 查询条件
     * @return 查询对象
     */
    private LambdaQueryWrapper<Notebook> getQueryParams(QueryNotebookForm form) {
        LambdaQueryWrapper<Notebook> qw = new QueryWrapper<Notebook>().lambda().eq(Notebook::getDeleted, Boolean.FALSE);
        if (form.getUseUser()) {
            if (form.getMyFlag()) {
                qw.eq(Notebook::getUserId, UserUtil.getUserInfo().getId());
            } else {
                //仅查询被共享的
                List<String> ids = shareService.getShareByUserId(UserUtil.getUserInfo().getId());
                if (CollectionUtils.isEmpty(ids)) {
                    //暂无分享, 使查询结果为空
                    ids.add(UUID.randomUUID().toString());
                }
                qw.in(Notebook::getId, ids);
            }
        }
        if (!CollectionUtils.isEmpty(form.getPublishStatusList())) {
            qw.in(Notebook::getPublishStatus, form.getPublishStatusList());
        }
        return qw;
    }

    /**
     * 保存日记记录其他信息
     *
     * @param form       保存参数信息
     * @param notebookId 日记记录ID
     */
    private void saveOther(AddNotebookForm form, String notebookId) {
        imageService.saveImageList(form.getImagesFiles(), notebookId);
        shareService.saveShareList(form.getShareIdList(), notebookId);
    }

    /**
     * 检查参数
     *
     * @param form 请求参数
     */
    private void checkParams(AddNotebookForm form) {
        if (form.getPublishWechatFlag()) {
            if (ObjectUtils.isEmpty(form.getPublishTitle())) {
                throw new BusinessException(MyResponseCode.BUSINESS_ERROR, "请输入同步发表文章标题!");
            }
            if (CollectionUtils.isEmpty(form.getImagesFiles())) {
                throw new BusinessException(MyResponseCode.BUSINESS_ERROR, "请选择同步发表文章图片");
            }
        }
    }

    /**
     * 发表文章到微信公众号
     *
     * @param notebookId 日记ID
     */
    private void publishToWeChat(String notebookId) {
        //等待5秒再执行新增草稿
        ThreadUtil.safeSleep(NumberConstant.FIVE_THOUSAND);
        NotebookDTO entity = this.getEntityById(notebookId);
        WechatDevelopConfigDTO config = configService.getConfigByUser(entity.getUserId());
        //准备日记参数转为微信图文文章的参数
        if (entity.getPublishWechatFlag()) {
            //用户选择同步发表到微信
            if (!ObjectUtils.isEmpty(config.getEnableFlag()) && config.getEnableFlag()) {
                Notebook base = super.get(notebookId);
                ArticleDraftForm form = new ArticleDraftForm();
                form.setAppId(config.getAppId());
                form.setTitle(entity.getPublishTitle());
                form.setAuthor(entity.getUserNickName());
                form.setContent(entity.getContent());
                form.setImageList(entity.getImagesFiles());
                try {
                    String publishId = apiService.pushArticle(form);
                    base.setPublishId(publishId);
                    base.setPublishStatus(WeChatPublishStatusEnum.PUBLISHING.getSn());
                } catch (Exception e) {
                    base.setPublishStatus(WeChatPublishStatusEnum.PUBLISH_FAILURE.getSn());
                    base.setPublishErrorMsg(e.getMessage());
                }
                super.update(base);
            }
        }
    }
}
